package com.bjsxt;
/**生产者与消费者的线程并发协作模式*/
/*线程并发协作（也叫线程通信）
* 生产者消费者模式：
* 1，生产者消费共享同一个资源，并且生产者和消费者之间相互依赖，互为条件
* 2，对于生产者，没有生产产品之前，消费者要进入等待状态，而生产了产品之后
* 又需要马上通知消费者消费。
* 3，对于消费者，在消费之后，要通知生产者已经消费结束，需要继承生产新产品
* 以供消费。
* 4，在生产者消费者问题中，仅有synchronized是不够的，还要外套wait（）和notify().
* synchronized可阻止并发更新同一个共享资源，实现了同步但是synchronized不能用来实现不
* 同线程之间的消息传递（通信）
* 5，线程之间的消息传递方法：
* final void wait()    表示线程一直等待，直到得到其他线程通知
* void wait(long timeout)  线程等待指定毫秒参数的时间
* final void wait(long timeout,int nanos)  线程等待指定毫秒,微秒的时间
* final void notify()     唤醒一个处于等待状态的线程
* final void notifyAll()   唤醒同一个对象上所有调用wait()方法的线程，优先
*                           级别高的线程优先运行
* 6，以上方法均是java。lang.Object类的方法。
* 都只能在（synchronized）同步方法或者是同步代码块中使用，否则会抛出异常*/
//以卖馒头为例
class ManTou{
    private int id;//馒头个数
    public ManTou(int id){
        this.id=id;
    }
    public int getId(){
        return this.id;
    }
}
/*定义缓冲区类*/
class SyncSlack{
    //定义存放馒头的盒子
    private ManTou[] mt = new ManTou[10];
    //定义盒子索引
    private int index;
    /*放镘头  要用synchronized 因为存放与取要有顺序*/
    //方法里的synchronized 的对象锁是this(默认)
public synchronized void push(ManTou manTou){
    //判断盒子是否已满
    while (this.index==this.mt.length) {
        try {
            // wait()是继承Object类的方法，不是Thread
            /*语法：wait()，必须要在synchronized 块中调用，
             * wait执行后，线程会持有的对象锁释放，并进入阻塞状态
             * 其他需要该线程 对象锁 的线程就可以继续运行*/
            this.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
        //如果取馒头的方法处于等待状态，而且放馒头满了，叫醒有相同对象锁的线程
       //唤醒取馒头的线程
        //notify()是继承Object类的方法
        /*语法：该方法必须要在synchronized 块中调用
        * 该方法会唤醒处于等待状态队列中的一个线程*/
        this.notify();
        //数组里放馒头
        this.mt[this.index] = manTou;
        this.index++;

}
    /*取馒头*/
    //返回馒头
    public synchronized ManTou pop(){
        //判断是否取完
        while (this.index==0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notify();
        this.index--;
        return this.mt[this.index];
    }

}
/*定义生产者线程类*/
class ShengChan extends Thread{
    private SyncSlack ss;//缓冲区类
    public ShengChan(SyncSlack ss){
        this.ss=ss;
    }

    @Override
    public void run() {
        //用循环生产每一个馒头
        for(int i=0;i<10;i++){
            System.out.println("生产馒头："+i);
            ManTou manTou = new ManTou(i);
            this.ss.push(manTou);
        }
    }
}
//消费者线程
class XiaoFei extends Thread{
    private SyncSlack ss;//从缓冲区中取对象
    public XiaoFei(SyncSlack ss){
        this.ss=ss;
    }
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            //从缓冲区取
            ManTou manTou = this.ss.pop();
            System.out.println("取馒头："+i);

        }
    }
}
public class ProduceThread {
    public static void main(String[] args) {
        //实例化缓冲区
        SyncSlack ss = new SyncSlack();
        new ShengChan(ss).start();
        new XiaoFei(ss).start();

    }
}
